package com.sayice.gomoku.web;

import com.alibaba.fastjson.JSON;
import com.sayice.gomoku.config.GomokuConfig;
import com.sayice.gomoku.pojo.Board;
import com.sayice.gomoku.service.BoardService;
import com.sayice.gomoku.service.impl.BoardServiceImpl;
import com.sayice.gomoku.utils.FileUploadUtils;
import com.sayice.gomoku.utils.FileUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;

/**
 * 处理棋盘业务请求
 */
@WebServlet(urlPatterns = "/boardServlet")
public class BoardServlet extends BaseServlet {
    private final BoardService boardService = new BoardServiceImpl();
    
    /**
     * 设置棋盘名
     */
    protected void setName(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        System.out.println("收到 setName 请求");
        int adminId = Integer.parseInt(req.getParameter("adminId").trim());
        int boardId = Integer.parseInt(req.getParameter("boardId").trim());
        String name = req.getParameter("name").trim();
        Board board = boardService.getBoard(boardId);
        // 棋盘名有变化时才修改
        if (!name.equals(board.getName())) {
            final String namePattern = "^[\\S]+$";
            if (!name.matches(namePattern)) {
                System.out.println("设置棋盘名失败: 棋盘名不合法");
                resp.getWriter().write(JSON.toJSONString(false));
                return;
            }
            if (boardService.existsName(name)) {
                System.out.println("设置棋盘名失败: 棋盘名已存在");
                resp.getWriter().write(JSON.toJSONString(false));
                return;
            }
            // 修改棋盘图片文件名
            // 棋盘图片所在文件夹的路径
            String boardImgPath = GomokuConfig.BOARD_IMG_PATH;
            final String fileSuffix = ".jpg";
            // 棋盘图片路径
            String filePath = boardImgPath + "/" + board.getName() + fileSuffix;
            // 必须先修改文件后修改数据库，因为修改文件名时会查询数据库中的原文件名
            if (!FileUtils.rename(filePath, name)) {
                resp.getWriter().write(JSON.toJSONString(false));
                return;
            }
            boardService.setName(adminId, boardId, name);
        }
        resp.getWriter().write(JSON.toJSONString(true));
    }
    
    /**
     * 设置价格
     */
    protected void setPrice(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        System.out.println("收到 setPrice 请求");
        int adminId = Integer.parseInt(req.getParameter("adminId").trim());
        int boardId = Integer.parseInt(req.getParameter("boardId").trim());
        BigDecimal price = new BigDecimal(req.getParameter("price").trim());
        Board board = boardService.getBoard(boardId);
        // 价格有变化时才修改
        if (!price.equals(board.getPrice())) {
            boardService.setPrice(adminId, boardId, price);
        }
        resp.getWriter().write(JSON.toJSONString(true));
    }
    
    /**
     * 购买棋盘
     */
    protected void buyBoard(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        int userId = Integer.parseInt(req.getParameter("userId").trim());
        int boardId = Integer.parseInt(req.getParameter("boardId").trim());
        // 判断是否已购买
        if (boardService.bought(boardId, userId)) {
            resp.getWriter().write(JSON.toJSONString(false));
            return;
        }
        boardService.buy(userId, boardId);
        resp.getWriter().write(JSON.toJSONString(true));
    }
    
    /**
     * 检查棋盘名是否已存在
     */
    protected void checkExists(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        System.out.println("收到 checkExists 请求");
        String name = req.getParameter("name").trim();
        boolean existsName = boardService.existsName(name);
        resp.getWriter().write(JSON.toJSONString(existsName));
    }
    
    /**
     * 上传棋盘图片
     */
    protected void upload(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        System.out.println("收到 upload 请求");
        FileUploadUtils.handleMultiPart(req, new FileUploadUtils.MultiPartHandler() {
            public void handle(int adminId, String name, BigDecimal price, FileItem boardImgFile) throws Exception {
                // 棋盘图片所在文件夹的路径
                String boardImgPath = GomokuConfig.BOARD_IMG_PATH;
                final String fileSuffix = ".jpg";
                final String namePattern = "^[\\S]+$";
                if (!name.matches(namePattern)) {
                    System.out.println("上传棋盘失败：棋盘名不合法");
                } else if (boardImgFile == null) {
                    System.out.println("上传棋盘失败：文件为空");
                } else if (!boardImgFile.getName().endsWith(fileSuffix)) {
                    System.out.println("上传棋盘失败：文件类型不合法");
                    System.out.println("原始文件名: " + boardImgFile.getName());
                } else if (boardService.existsName(name)) {
                    System.out.println("上传棋盘失败：棋盘名已存在");
                } else if (!FileUploadUtils.upload(boardImgPath, boardImgFile, name + fileSuffix)) {
                    System.out.println("上传棋盘文件失败");
                } else {
                    Board board = new Board(name, price, adminId, adminId);
                    boardService.upload(board);
                    System.out.println("上传棋盘成功");
                }
                req.setAttribute("adminId", adminId);
                req.getRequestDispatcher("/pages/manager/boardUpload.jsp").forward(req, resp);
            }
        });
    }
    
    /**
     * 更新棋盘图片
     */
    protected void updateImg(HttpServletRequest req, HttpServletResponse resp) throws InvocationTargetException, FileUploadException, IllegalAccessException, UnsupportedEncodingException {
        System.out.println("收到 updateImg 请求");
        FileUploadUtils.handleMultiPart(req, new FileUploadUtils.MultiPartHandler() {
            public void handle(int adminId, int boardId, FileItem boardImgFile) throws Exception {
                // 棋盘图片路径
                String boardImgPath = GomokuConfig.BOARD_IMG_PATH;
                final String fileSuffix = ".jpg";
                if (!boardImgFile.getName().endsWith(fileSuffix)) {
                    System.out.println("更新棋盘图片失败: 文件类型不合法");
                    System.out.println("原始文件名: " + boardImgFile.getName());
                    resp.getWriter().write(JSON.toJSONString(false));
                    return;
                }
                Board board = boardService.getBoard(boardId);
                if (!FileUploadUtils.upload(boardImgPath, boardImgFile, board.getName() + fileSuffix)) {
                    System.out.println("更新棋盘图片失败");
                    resp.getWriter().write(JSON.toJSONString(false));
                    return;
                }
                System.out.println("更新棋盘图片成功");
                // 更新最后修改者
                boardService.setModifier(boardId, adminId);
                resp.getWriter().write(JSON.toJSONString(true));
            }
        });
    }
    
    /**
     * 转到棋盘上传页面
     */
    protected void toUpload(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        int adminId = Integer.parseInt(req.getParameter("adminId").trim());
        req.setAttribute("adminId", adminId);
        req.getRequestDispatcher("/pages/manager/boardUpload.jsp").forward(req, resp);
    }
    
    /**
     * 转到棋盘编辑页面
     */
    protected void toEdit(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        int adminId = Integer.parseInt(req.getParameter("adminId").trim());
        int boardId = Integer.parseInt(req.getParameter("boardId").trim());
        Board board = boardService.getBoard(boardId);
        req.setAttribute("adminId", adminId);
        req.setAttribute("board", board);
        req.getRequestDispatcher("/pages/manager/boardEdit.jsp").forward(req, resp);
    }
}
